﻿using System;
using System.Collections.Generic;
using System.Text;

using MapCenterSystem.DataInfo;
using MapCenterSystem.DataAccess;
using MapCenterSystem.DefineType;

namespace MapCenterSytem.Process
{
    public class GraphNode
    {
        private static int IsRelated(Coordinate node1, Coordinate node2)
        {
            GraphNodeServiceEx graphNodeService = new GraphNodeServiceEx();
            return graphNodeService.IsRelated(node1, node2);
        }

        private static List<GraphNodeInfoEx> ShortestPath(List<GraphNodeInfoEx> lstChosen)
        {
            List<GraphNodeInfoEx> result = new List<GraphNodeInfoEx>();
            int lastIndex = lstChosen.Count - 1;
            GraphNodeInfoEx end = lstChosen[lastIndex];
            GraphNodeInfoEx start = lstChosen[0];
            result.Add(end);
            GraphNodeInfoEx node = end;
            while (!node.Equals(start))
            {
                node = node.Father;
                result.Add(node);
            }
            result.Reverse();
            return result;
        }

        public static List<GraphNodeInfoEx> ShortestPath(Coordinate from, Coordinate end)
        {
            GraphNodeServiceEx nodeService = new GraphNodeServiceEx();
            GraphNodeInfoEx nodeStart = nodeService.GetGraphNodeInfoEx(from);
            GraphNodeInfoEx nodeEnd = nodeService.GetGraphNodeInfoEx(end);

            nodeStart.Father = null;
            nodeStart.CalculateHeuristic(nodeEnd);
            nodeStart.G = 0;
            nodeStart.F = nodeStart.H + nodeStart.G;
            
            List<GraphNodeInfoEx> lstPriority = new List<GraphNodeInfoEx>();
            List<GraphNodeInfoEx> lstChosen = new List<GraphNodeInfoEx>();
            lstPriority.Add(nodeStart);

            int count = 0;
            while (lstPriority.Count > 0 && count < 2000)
            {
                count++;
                GraphNodeInfoEx currentNode = new GraphNodeInfoEx(lstPriority[0]);
                lstPriority.RemoveAt(0);
                lstChosen.Add(currentNode);                
                
                if (currentNode.Equals(nodeEnd))
                {
                    return ShortestPath(lstChosen);
                }

                List<GraphNodeInfoEx> lstRelation = nodeService.GetListNodeRelate(currentNode.Location);
                int IDStreet = IsRelated(currentNode.Location, nodeEnd.Location);
                if (IsRelated(currentNode.Location, nodeEnd.Location) != 0)
                {
                    lstRelation.Add(nodeEnd);
                    nodeEnd.IDStreet = IDStreet;
                }

                foreach (GraphNodeInfoEx node in lstRelation)
                {
                    node.CalculateHeuristic(nodeEnd);
                    node.G = currentNode.G + (float)Coordinate.Distance(currentNode.Location, node.Location);
                    node.F = node.H + node.G;
                    node.Father = currentNode;

                    if(!lstPriority.Contains(node) && !lstChosen.Contains(node))
                    {
                        lstPriority.Add(node);
                    }

                    if(lstPriority.Contains(node) && node.F < lstPriority[lstPriority.IndexOf(node)].F)
                    {
                        lstPriority.Remove(node);
                        lstPriority.Add(node);
                    }

                    if (lstChosen.Contains(node) && node.F < lstChosen[lstChosen.IndexOf(node)].F)
                    {
                        lstChosen.Remove(node);
                        lstChosen.Add(node);
                    }
                }
                lstPriority.Sort();
            }
            return null;
        }
    }
}
